#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
视频文件同步检查脚本
功能：
1. 扫描源目录下所有文件，将文件名和大小存储到Redis
2. 检查目标目录文件是否在Redis中存在
3. 复制不存在的文件到遗漏目录
"""

import os
import shutil
import hashlib
import redis
from pathlib import Path
import json
from typing import Dict, Set

class VideoSyncChecker:
    def __init__(self, redis_host='127.0.0.1', redis_port=6379, redis_db=0):
        """
        初始化视频同步检查器
        
        Args:
            redis_host: Redis服务器地址
            redis_port: Redis端口
            redis_db: Redis数据库编号
        """
        self.redis_client = redis.Redis(
            host=redis_host, 
            port=redis_port, 
            db=redis_db, 
            decode_responses=True
        )
        self.source_dir = '/Volumes/jdssd5/视频/'
        self.target_dir = '/Volumes/JerryLi/Video/twitter'
        self.missing_dir = '/Volumes/jdssd5/视频/遗漏/'
        
        # 确保遗漏目录存在
        os.makedirs(self.missing_dir, exist_ok=True)
        
        # Redis键前缀
        self.redis_key_prefix = 'video_files:'
    
    def get_file_key(self, filename: str, filesize: int) -> str:
        """
        生成文件的Redis键
        
        Args:
            filename: 文件名
            filesize: 文件大小
            
        Returns:
            Redis键字符串
        """
        # 使用文件名和大小生成唯一键
        key_data = f"{filename}:{filesize}"
        return f"{self.redis_key_prefix}{hashlib.md5(key_data.encode()).hexdigest()}"
    
    def scan_source_directory(self) -> int:
        """
        扫描源目录下的所有文件，将文件信息存储到Redis
        
        Returns:
            扫描到的文件数量
        """
        print(f"开始扫描源目录: {self.source_dir}")
        
        if not os.path.exists(self.source_dir):
            print(f"源目录不存在: {self.source_dir}")
            return 0
        
        file_count = 0
        
        # 递归遍历所有文件
        for root, dirs, files in os.walk(self.source_dir):
            for file in files:
                file_path = os.path.join(root, file)
                
                try:
                    # 获取文件大小
                    file_size = os.path.getsize(file_path)
                    
                    # 生成Redis键
                    redis_key = self.get_file_key(file, file_size)
                    
                    # 存储文件信息到Redis
                    file_info = {
                        'filename': file,
                        'size': file_size,
                        'path': file_path,
                        'relative_path': os.path.relpath(file_path, self.source_dir)
                    }
                    
                    self.redis_client.set(redis_key, json.dumps(file_info, ensure_ascii=False))
                    file_count += 1
                    
                    if file_count % 100 == 0:
                        print(f"已处理 {file_count} 个文件...")
                        
                except (OSError, IOError) as e:
                    print(f"处理文件时出错 {file_path}: {e}")
                    continue
        
        print(f"源目录扫描完成，共处理 {file_count} 个文件")
        return file_count
    
    
    def check_target_directory(self) -> int:
        """
        检查目标目录中的文件是否在Redis中存在，复制不存在的文件
    
        Returns:
            复制的文件数量
        """
        print(f"开始检查目标目录: {self.target_dir}")
    
        if not os.path.exists(self.target_dir):
            print(f"目标目录不存在: {self.target_dir}")
            return 0
    
        copied_count = 0
        checked_count = 0
    
        # 递归遍历目标目录所有文件
        for root, dirs, files in os.walk(self.target_dir):
            for file in files:
                file_path = os.path.join(root, file)
    
                try:
                    # 获取文件大小
                    file_size = os.path.getsize(file_path)
    
                    # 生成Redis键
                    redis_key = self.get_file_key(file, file_size)
    
                    # 检查Redis中是否存在
                    if not self.redis_client.exists(redis_key):
                        # 检查遗漏目录是否已存在同名文件
                        dest_path = os.path.join(self.missing_dir, file)
                        if not os.path.exists(dest_path):
                            # 文件不存在，需要复制
                            self._copy_missing_file(file_path, file)
                            copied_count += 1
                            print(f"复制遗漏文件: {file}")
                            # 复制后将特征信息存入Redis
                            file_info = {
                                'filename': file,
                                'size': file_size,
                                'path': file_path,
                                'relative_path': os.path.relpath(file_path, self.target_dir)
                            }
                            self.redis_client.set(redis_key, json.dumps(file_info, ensure_ascii=False))
                        else:
                            print(f"遗漏目录已存在同名文件，跳过: {file}")
    
                    checked_count += 1
    
                    if checked_count % 100 == 0:
                        print(f"已检查 {checked_count} 个文件，复制了 {copied_count} 个遗漏文件...")
    
                except (OSError, IOError) as e:
                    print(f"处理文件时出错 {file_path}: {e}")
                    continue
    
        print(f"目标目录检查完成，共检查 {checked_count} 个文件，复制了 {copied_count} 个遗漏文件")
        return copied_count
    
    def _copy_missing_file(self, source_path: str, filename: str):
        """
        复制遗漏的文件到遗漏目录
    
        Args:
            source_path: 源文件路径
            filename: 文件名
        """
        try:
            dest_path = os.path.join(self.missing_dir, filename)
    
            # 如果目标文件已存在，添加序号
            counter = 1
            original_dest = dest_path
            while os.path.exists(dest_path):
                name, ext = os.path.splitext(original_dest)
                dest_path = f"{name}_{counter}{ext}"
                counter += 1
    
            # 复制文件
            shutil.copy2(source_path, dest_path)
    
        except (OSError, IOError) as e:
            print(f"复制文件失败 {source_path} -> {dest_path}: {e}")
    
    def clear_redis_data(self):
        """
        清除Redis中的文件数据
        """
        print("清除Redis中的文件数据...")
        
        # 获取所有相关键
        keys = self.redis_client.keys(f"{self.redis_key_prefix}*")
        
        if keys:
            self.redis_client.delete(*keys)
            print(f"已清除 {len(keys)} 条记录")
        else:
            print("没有找到相关数据")
    
    def get_redis_stats(self) -> Dict:
        """
        获取Redis中的统计信息

        Returns:
            统计信息字典
        """
        keys = self.redis_client.keys(f"{self.redis_key_prefix}*")
        # 统计所有key的内存用量
        total_memory = 0
        for k in keys:
            try:
                total_memory += self.redis_client.memory_usage(k)
            except Exception:
                pass  # 某些redis版本可能不支持memory_usage
        return {
            'total_files': len(keys),
            'redis_memory_usage': total_memory if total_memory > 0 else 'N/A'
        }
        
    def run_full_sync(self):
        """
        执行完整的同步检查流程
        """
        print("=== 开始视频文件同步检查 ===")
        
        try:
            # 测试Redis连接
            self.redis_client.ping()
            print("Redis连接成功")
        except redis.ConnectionError:
            print("Redis连接失败，请检查Redis服务是否启动")
            return
        
        # 1. 扫描源目录
        source_count = self.scan_source_directory()
        
        if source_count == 0:
            print("源目录中没有文件，退出")
            return
        
        # 2. 检查目标目录
        copied_count = self.check_target_directory()
        
        # 3. 显示统计信息
        stats = self.get_redis_stats()
        print(f"\n=== 同步检查完成 ===")
        print(f"源目录文件数: {source_count}")
        print(f"Redis中文件数: {stats['total_files']}")
        print(f"复制的遗漏文件数: {copied_count}")
        print(f"遗漏文件保存位置: {self.missing_dir}")


def main():
    """
    主函数
    """
    # 创建同步检查器实例
    checker = VideoSyncChecker()
    
    # 执行完整同步检查
    checker.run_full_sync()


if __name__ == '__main__':
    main()